/**
 * 文件导出
 */
import models from 'src-ssr/db/sequelize';
import * as tools from 'src-ssr/util/common';
import exportExcel from './exportExcel';
import excelTemplater from './excelTemplater';
import word from './wordTemplater';
import otp from './officeToPdf';
import path from 'path';
import fs from 'fs';
import * as mathjs from 'mathjs';

// 用正则表达式 过滤特殊字符
function stripScript (s) {
  // eslint-disable-next-line prefer-regex-literals
  const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#￥……&*（）——|{}【】‘；：”“’。，、？]")
  let rs = '';
  for (let i = 0; i < s.length; i++) {
    rs = rs + s.substr(i, 1).replace(pattern, '');
  }

  // 过滤表情
  rs = rs.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '');
  return rs;
}

/**
 * 取数据导出模板文件的配置
 * @param {string} uid 模板的uid，可空
 * @param {string} module 模块名，可空
 * @param {string} entry 入口标识，可空
 * @param {string} tid 类型 0-系统用户 大于0-租户id
 * @returns 返回配置信息
 */
async function getDocsConfig ({ uid, module, entry, tid = 0 }) {
  const config = await models.m_config.findOne({ where: { key: 'doc', tenant_id: tid } });

  let docs = config.value || [];

  // 优先过滤出指定uid
  if (uid) {
    docs = docs.filter(v => v.uid == uid && v.active == 'yes');
  }

  // 再过滤出同名module
  if (module) {
    docs = docs.filter(v => v.module == module && v.active == 'yes');
  }

  // 最后过滤出指定入口的
  if (entry) {
    docs = docs.filter(v => v.entry == entry && v.active == 'yes');
  }

  docs.sort((a, b) => !a.default.localeCompare(b.default)); // 把默认的排到前面
  return docs;
}

/**
 * 导出文件
 * @param {object} data 数据，其中明细数据放在 details 里
 * @param {object} defaultCfg 默认配置 { template, output, params } template:模板文件 output:输出文件名 params:参数
 * @param {object} {}.module 模块名
 * @param {object} {}.entry 入口名
 * @param {object} {}.uid 入口uid
 * @param {boolean} pdf 是否转pdf
 */
export const doExport = async (data, defaultCfg, { uid, module, entry }, pdf = true) => {
  const currentConfig = { ...defaultCfg };
  const docConfig = await getDocsConfig({ uid, module, entry });
  const rootFolder = process.env.NODE_ENV === 'development' ? path.join(path.resolve(__dirname, '../..')) : path.join(path.resolve(__dirname, '..'));

  if (docConfig.length > 0) {
    if (docConfig[0].template) currentConfig.template = docConfig[0].template;
    if (docConfig[0].output) currentConfig.output = docConfig[0].output;
    if (docConfig[0].params) currentConfig.params = docConfig[0].params;
  }

  // 替换输出文件名中的变量
  for (const key in data) {
    if (currentConfig.output.indexOf(`{${key}}`) >= 0) {
      let keyWord = data[key];
      if (keyWord.length > 100) {
        keyWord = keyWord.slice(0, 100);
      }
      currentConfig.output = stripScript(currentConfig.output.replace(new RegExp(`{${key}}`, 'g'), keyWord));
    }
  }

  let outfile = null;
  const ext = path.extname(currentConfig.template);
  if (ext === '.xlsx') { // excel处理导出
    // 生成报告
    outfile = excelTemplater.generateFile(currentConfig.template, data, currentConfig.output);

    // 插入图片，包含公章等 [{need: true, type: 'master', field, file, position: ["h", {width, height}, 3.8, {col, row}], type, field, file}] position参考exportExcel.js的addImage参数
    // row里两个宏 {len}表示明细表行数 {idx}表示明细行号
    // type:master表示主表数据 field,file二选一，field表示字段名 file表示指定的文件名
    // type:detail表示明细数据 field，具体的字段名

    const excelInfo = await exportExcel.exportDefineExcel({
      fromFile: `../..${outfile.url}`,
      filename: currentConfig.output,
      sheets: [{
        label: 'Sheet1',
        data: null
      }]
    }, (book, sheet, name) => {
      return new Promise(resolve => {
        // 插入图片
        if (currentConfig.params && currentConfig.params.images) {
          for (const item of currentConfig.params.images.filter(v => v.need)) { // 只处理需要处理的
            let { col, row } = item.position.position;
            if (typeof row === 'string' && row.indexOf('{len}') >= 0) {
              row = mathjs.evaluate(row.replace(/{len}/g, data.details.length));// 把数据行数增加进去
            }

            // 单一图片
            if (item.type === 'master') {
              if (item.file) {
                exportExcel.addImageToSheet([{ image: item.file }], item.position.direction, item.position.size, { col, row }, book, sheet);
              } else if (item.field) {
                exportExcel.addImageToSheet(data[item.field], item.position.direction, item.position.size, { col, row }, book, sheet);
              }
            } else if (item.type === 'detail') { // 明细里插入数据
              data.details.forEach((detailRow, idx) => {
                if (detailRow[item.field]) {
                  row = mathjs.evaluate(row.replace(/{idx}/g, idx));
                  exportExcel.addImageToSheet(detailRow[item.field], item.position.direction, item.position.size, { col, row }, book, sheet);
                }
              });
            }
          }
        }

        if (currentConfig.params && currentConfig.params.autoHeight) {
          /** 字符太多，自动调整行数
           * { type: 'master', cell: 'A1', maxChar: 12, lineHeight: 15 }
           * type 类型 主表
           * cell 单元格地址两种写法 1、A1 2、{ line: 8, column: 11 } 这种写法会把明细行数加上去
           * maxChar 单行最长的字符数，一个中文的长度为2
           * lineHeight 单行的高度
           *
           * { type: 'detail', beginLine: 8, column: 11, maxChar: 12, lineHeight: 15 }
           * type 类型 明细表
           * beginLine 明细行开始行号（非标题行）,从1开始
           * column 列号，从1开始
           * maxChar 单行最长的字符数，一个中文的长度为2
           * lineHeight 单行的高度
           */
          for (const def of currentConfig.params.autoHeight) {
            if (def.type === 'master') {
              let cell = null;
              let row = null;
              if (typeof def.cell === 'string') {
                cell = sheet.getCell(def.cell);
                row = sheet.getRow(Number(def.cell.replace(/[^0-9]/ig, '')));
              } else {
                // cell = sheet.getCell(`${tools.convertDSTo26BS(def.cell.column)}${def.cell.line + data.details.length}`);
                row = sheet.getRow(def.cell.line + data.details.length);
                cell = row.getCell(def.cell.column);
              }
              const needHeight = Math.ceil(tools.getStrLength(cell.value || '') / def.maxChar) * def.lineHeight;
              if (row.height < needHeight || !row.height) row.height = needHeight;
            } else if (def.type === 'detail') {
              for (let i = 0; i < data.details.length; i++) {
                const row = sheet.getRow(def.beginLine + i);
                const cell = row.getCell(def.column);
                const needHeight = Math.ceil(tools.getStrLength(cell.value || '') / def.maxChar) * def.lineHeight;
                if (row.height < needHeight || !row.height) row.height = needHeight;
              }
            }
          }
        }
        /**
         * 合并单元格
         * 参数：merge: { master: [[fromRow, fromCol, toRow, toCol]], detail: { begin, cols: [{no, type, field}] } }
         * master中，fromRow,toRow支持行数的宏{len}，len即从表的数据行数
         * detail中，
         *      begin为数据行开始的行，
         *      cols为一数组，哪些数据相同的列进行合并,
         *          no 为列号，
         *          type 为合并的方式 all-所有(不填即默认)，one-只保留第一行数据，sum-累计
         *          field 字段名，type为sum时，用于累计数据
         */
        if (currentConfig.params && currentConfig.params.merge) {
          const { master, detail } = currentConfig.params.merge;
          // 合并主表的格式
          if (master && master.length > 0) {
            for (const cell of master) {
              let [fromRow, fromCol, toRow, toCol] = cell;
              fromRow = mathjs.evaluate(fromRow.replace(/{len}/g, data.details.length));
              toRow = mathjs.evaluate(fromRow.replace(/{len}/g, data.details.length));
              // 按开始行，开始列，结束行，结束列合并
              sheet.mergeCells(fromRow, fromCol, toRow, toCol);
            }
          }
          // 合并从表的格式
          if (detail) {
            const sameRow = {}; // 相同物料id的行号
            data.details.forEach((v, idx) => {
              if (sameRow[v.material_id]) {
                sameRow[v.material_id].push(idx);
              } else {
                sameRow[v.material_id] = [idx];
              }
            });

            const { begin, cols } = detail;
            for (const key in sameRow) {
              if (sameRow[key].length > 1) {
                for (const col of cols) {
                  // 只保留一个值
                  if (['one', 'sum'].includes(col.type)) {
                    for (let i = 1; i < sameRow[key].length; i++) {
                      const cellIdx = `${tools.convertDSTo26BS(col.no)}${Number(begin) + Number(sameRow[key][i])}`;
                      sheet.getCell(cellIdx).value = '';
                    }
                  }
                  // 累计值
                  if (col.type === 'sum') {
                    const cellIdx = `${tools.convertDSTo26BS(col.no)}${Number(begin) + Number(sameRow[key][0])}`;
                    const sum = sameRow[key].reduce((a, b) => a + Number(data.details[b][col.field]), 0);
                    // console.log(cellIdx, sum);
                    sheet.getCell(cellIdx).value = sum;
                  }

                  // 按开始行，开始列，结束行，结束列合并
                  sheet.mergeCells(begin + sameRow[key][0], col.no, begin + sameRow[key][sameRow[key].length - 1], col.no);
                }
              }
            }
          }
        }

        resolve();
      });
    });
    fs.unlinkSync(path.join(rootFolder, outfile.url));
    outfile.url = excelInfo.url;
  } else if (ext === '.docx') { // word处理导出
    // 生成报告
    outfile = await word.generateFile2(currentConfig.template, data, currentConfig.output, global.domainHost);
  }

  if (pdf && outfile) {
    const mode = currentConfig.params && currentConfig.params.convertPdfMode || 'libreoffice'; // 转pdf的模式
    const pdfPath = await otp.convertToPdf(outfile.url, mode);
    if (pdfPath) {
      outfile.url = pdfPath;
      outfile.file = outfile.file + '.pdf';
    }
  }

  return outfile;
};
